import "#components/ak-nav-buttons";
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";

import { EVENT_WS_MESSAGE } from "#common/constants";
import { globalAK } from "#common/global";
import { getConfigForUser, UIConfig, UserDisplay } from "#common/ui/config";
import { me } from "#common/users";

import { AKElement } from "#elements/Base";
import { WithBrandConfig } from "#elements/mixins/branding";
import { isAdminRoute } from "#elements/router/utils";
import { themeImage } from "#elements/utils/images";

import type { PageHeaderInit, SidebarToggleEventDetail } from "#components/ak-page-header";

import { SessionUser } from "@goauthentik/api";

import { msg } from "@lit/localize";
import { css, CSSResult, html, nothing, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators.js";

import PFAvatar from "@patternfly/patternfly/components/Avatar/avatar.css";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFContent from "@patternfly/patternfly/components/Content/content.css";
import PFDrawer from "@patternfly/patternfly/components/Drawer/drawer.css";
import PFDropdown from "@patternfly/patternfly/components/Dropdown/dropdown.css";
import PFNotificationBadge from "@patternfly/patternfly/components/NotificationBadge/notification-badge.css";
import PFPage from "@patternfly/patternfly/components/Page/page.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";

/**
 * A global navbar component at the top of the page.
 *
 * Internally, this component listens for the `ak-page-header` event, which is
 * dispatched by the `ak-page-header` component.
 */
@customElement("ak-page-navbar")
export class AKPageNavbar
    extends WithBrandConfig(AKElement)
    implements PageHeaderInit, SidebarToggleEventDetail
{
    //#region Static Properties

    private static elementRef: AKPageNavbar | null = null;

    static readonly setNavbarDetails = (detail: Partial<PageHeaderInit>): void => {
        const { elementRef } = AKPageNavbar;
        if (!elementRef) {
            console.debug(
                `ak-page-header: Could not find ak-page-navbar, skipping event dispatch.`,
            );
            return;
        }

        const { header, description, icon, iconImage } = detail;

        elementRef.header = header;
        elementRef.description = description;
        elementRef.icon = icon;
        elementRef.iconImage = iconImage || false;
        elementRef.hasIcon = !!icon;
    };

    static styles: CSSResult[] = [
        PFBase,
        PFButton,
        PFPage,
        PFDrawer,

        PFNotificationBadge,
        PFContent,
        PFAvatar,
        PFDropdown,
        css`
            :host {
                position: sticky;
                top: 0;
                z-index: var(--pf-global--ZIndex--lg);
                --pf-c-page__header-tools--MarginRight: 0;
                --ak-brand-logo-height: var(--pf-global--FontSize--4xl, 2.25rem);
                --ak-brand-background-color: var(--pf-c-page__sidebar--m-light--BackgroundColor);
                --host-navbar-height: var(--ak-c-page-header--height, 7.5rem);
            }

            :host([theme="dark"]) {
                --ak-brand-background-color: var(--pf-c-page__sidebar--BackgroundColor);
                --pf-c-page__sidebar--BackgroundColor: var(--ak-dark-background-light);
                color: var(--ak-dark-foreground);
            }

            .main-content {
                border-bottom: var(--pf-global--BorderWidth--sm);
                border-bottom-style: solid;
                border-bottom-color: var(--pf-global--BorderColor--100);
                background-color: var(--pf-c-page--BackgroundColor);

                display: flex;
                flex-direction: row;

                display: grid;
                column-gap: var(--pf-global--spacer--sm);
                grid-template-columns: [brand] auto [toggle] auto [primary] 1fr [secondary] auto;
                grid-template-rows: auto auto;
                grid-template-areas:
                    "brand toggle primary secondary"
                    "brand toggle description secondary";

                @media (min-width: 769px) {
                    height: var(--host-navbar-height);
                }

                @media (max-width: 768px) {
                    row-gap: var(--pf-global--spacer--xs);

                    align-items: center;
                    grid-template-areas:
                        "toggle primary secondary"
                        "toggle description description";
                    justify-content: space-between;
                    width: 100%;
                }
            }

            .items {
                display: block;

                &.primary {
                    grid-column: primary;
                    grid-row: primary / description;

                    align-self: center;
                    padding-block: var(--pf-global--spacer--md);

                    @media (max-width: 768px) {
                        padding-block: var(--pf-global--spacer--sm);
                    }

                    &.block-sibling {
                        align-self: end;
                    }

                    @media (min-width: 426px) {
                        &.block-sibling {
                            padding-block-end: 0;
                            grid-row: primary;
                        }
                    }

                    .accent-icon {
                        height: 1.2em;
                        width: 1em;

                        @media (max-width: 768px) {
                            display: none;
                        }
                    }
                }

                &.page-description {
                    padding-top: 0.3em;
                    grid-area: description;
                    margin-block-end: var(--pf-global--spacer--md);

                    display: box;
                    display: -webkit-box;
                    line-clamp: 2;
                    -webkit-line-clamp: 2;
                    box-orient: vertical;
                    -webkit-box-orient: vertical;
                    overflow: hidden;

                    @media (max-width: 425px) {
                        display: none;
                    }

                    @media (min-width: 769px) {
                        text-wrap: balance;
                    }
                }

                &.secondary {
                    grid-area: secondary;
                    flex: 0 0 auto;
                    justify-self: end;
                    padding-block: var(--pf-global--spacer--sm);
                    padding-inline-end: var(--pf-global--spacer--sm);

                    @media (min-width: 769px) {
                        align-content: center;
                        padding-block: var(--pf-global--spacer--md);
                        padding-inline-end: var(--pf-global--spacer--xl);
                    }
                }
            }

            .brand {
                grid-area: brand;
                background-color: var(--ak-brand-background-color);
                height: 100%;
                width: var(--pf-c-page__sidebar--Width);
                align-items: center;
                padding-inline: var(--pf-global--spacer--sm);

                display: flex;
                justify-content: center;

                &.pf-m-collapsed {
                    display: none;
                }

                @media (max-width: 1199px) {
                    display: none;
                }
            }

            .sidebar-trigger {
                grid-area: toggle;
                height: 100%;
            }

            .logo {
                flex: 0 0 auto;
                height: var(--ak-brand-logo-height);

                & img {
                    height: 100%;
                }
            }

            .sidebar-trigger,
            .notification-trigger {
                font-size: 1.5rem;
            }

            .notification-trigger.has-notifications {
                color: var(--pf-global--active-color--100);
            }

            .pf-c-content .page-title {
                display: box;
                display: -webkit-box;
                line-clamp: 2;
                -webkit-line-clamp: 2;
                box-orient: vertical;
                -webkit-box-orient: vertical;
                overflow: hidden;
            }

            h1 {
                display: flex;
                flex-direction: row;
                align-items: center !important;
            }
        `,
    ];

    //#endregion

    //#region Properties

    @state()
    icon?: string;

    @state()
    iconImage = false;

    @state()
    header?: string;

    @state()
    description?: string;

    @state()
    hasIcon = true;

    @property({
        type: Boolean,
    })
    public open?: boolean;

    @state()
    protected session?: SessionUser;

    @state()
    protected uiConfig!: UIConfig;

    //#endregion

    //#region Private Methods

    #setTitle(header?: string) {
        let title = this.brandingTitle;

        if (isAdminRoute()) {
            title = `${msg("Admin")} - ${title}`;
        }
        // Prepend the header to the title
        if (header) {
            title = `${header} - ${title}`;
        }
        document.title = title;
    }

    #toggleSidebar() {
        this.open = !this.open;

        this.dispatchEvent(
            new CustomEvent<SidebarToggleEventDetail>("sidebar-toggle", {
                bubbles: true,
                composed: true,
                detail: { open: this.open },
            }),
        );
    }

    //#endregion

    //#region Lifecycle

    public connectedCallback(): void {
        super.connectedCallback();
        AKPageNavbar.elementRef = this;

        window.addEventListener(EVENT_WS_MESSAGE, () => {
            this.firstUpdated();
        });
    }

    public disconnectedCallback(): void {
        super.disconnectedCallback();
        AKPageNavbar.elementRef = null;
    }

    public async firstUpdated() {
        this.session = await me();
        this.uiConfig = getConfigForUser(this.session.user);
        this.uiConfig.navbar.userDisplay = UserDisplay.none;
    }

    willUpdate() {
        // Always update title, even if there's no header value set,
        // as in that case we still need to return to the generic title
        this.#setTitle(this.header);
    }

    //#endregion

    //#region Render

    renderIcon() {
        if (this.icon) {
            if (this.iconImage && !this.icon.startsWith("fa://")) {
                return html`<img
                    aria-hidden="true"
                    class="accent-icon pf-icon"
                    src="${this.icon}"
                    alt="page icon"
                />`;
            }

            const icon = this.icon.replaceAll("fa://", "fa ");

            return html`<i class="accent-icon ${icon}"></i>`;
        }
        return nothing;
    }

    render(): TemplateResult {
        return html` <slot></slot>
            <div role="banner" aria-label="Main" class="main-content">
                <aside role="presentation" class="brand ${this.open ? "" : "pf-m-collapsed"}">
                    <a aria-label="${msg("Home")}" href="#/">
                        <div class="logo">
                            <img
                                src=${themeImage(this.brandingLogo)}
                                alt="${msg("authentik Logo")}"
                                loading="lazy"
                            />
                        </div>
                    </a>
                </aside>
                <button
                    aria-controls="global-nav"
                    class="sidebar-trigger pf-c-button pf-m-plain"
                    @click=${this.#toggleSidebar}
                    aria-label=${this.open ? msg("Collapse navigation") : msg("Expand navigation")}
                    aria-expanded=${this.open ? "true" : "false"}
                >
                    <i aria-hidden="true" class="fas fa-bars"></i>
                </button>

                <div class="items primary pf-c-content ${this.description ? "block-sibling" : ""}">
                    <h1 aria-labelledby="page-navbar-heading" class="page-title">
                        ${this.hasIcon
                            ? html`<slot aria-hidden="true" name="icon">${this.renderIcon()}</slot>`
                            : nothing}
                        <span id="page-navbar-heading">${this.header}</span>
                    </h1>
                </div>
                ${this.description
                    ? html`<div
                          role="heading"
                          aria-level="2"
                          aria-label="${this.description}"
                          class="items page-description pf-c-content"
                      >
                          <p>${this.description}</p>
                      </div>`
                    : nothing}

                <div class="items secondary">
                    <div class="pf-c-page__header-tools-group">
                        <ak-nav-buttons .uiConfig=${this.uiConfig} .me=${this.session}>
                            <a
                                class="pf-c-button pf-m-secondary pf-m-small pf-u-display-none pf-u-display-block-on-md"
                                href="${globalAK().api.base}if/user/"
                                slot="extra"
                            >
                                ${msg("User interface")}
                            </a>
                        </ak-nav-buttons>
                    </div>
                </div>
            </div>`;
    }

    //#endregion
}

declare global {
    interface HTMLElementTagNameMap {
        "ak-page-navbar": AKPageNavbar;
    }
}
